//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// Resource manager.
//

# include "StdAfx.h"
# include "Resource.h"
# include "ResMan.h"
# include "ParseHelpers.h"
# include "Menu.h"
# include "Settings.h"
# include "Globals.h"

HINSTANCE g_hResInst;

struct CLangData {
	string_t strRLL;
	string_t strName;
	LANGID liLangId;
};

typedef std::vector<CLangData> vecLanguages_t;
static vecLanguages_t g_vecLanguages;
static size_t g_cCurrentLanguage;

const LANGID c_liEnglishUS = MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US);

void InitResMan () {
	//
	// Save .exe module as resource one for English (U.S.)
	//
	char strProcessName [MAX_PATH + 1];
	::GetModuleFileName (NULL, strProcessName, MAX_PATH);
	const char * const pPathEnd = ::strrchr (strProcessName, '\\');

	char strLangName [32];
	if (! ::GetLocaleInfo (c_liEnglishUS, LOCALE_SLANGUAGE, strLangName, sizeof (strLangName)))
		::strcpy (strLangName, "English");

	g_vecLanguages.push_back (CLangData ());
	CLangData & ld = g_vecLanguages.back ();
	ld.liLangId = c_liEnglishUS;
	ld.strRLL = strProcessName;
	ld.strName = strLangName;

	g_cCurrentLanguage = 0;
	g_hResInst = g_hInst;

	//
	// Enumerate RLLs.
	//
	string_t strFilter;
	if (pPathEnd)
		strFilter.assign ((const char *) strProcessName, pPathEnd + 1);
	strFilter.append ("*.rll");

	WIN32_FIND_DATA fd;
	const HANDLE hFind = ::FindFirstFile (strFilter.c_str (), & fd);
	if (hFind == INVALID_HANDLE_VALUE)
		return;

	do {
		if (pPathEnd)
			strFilter.assign ((const char *) strProcessName, pPathEnd + 1);
		strFilter.append (fd.cFileName);

		unsigned long ulLangId = 0;
		const char * p = NULL;
		if (! ParseHex (fd.cFileName, fd.cFileName + sizeof (fd.cFileName), & p, ulLangId))
			continue;
		if (ulLangId == c_liEnglishUS)
			continue;

		// Get language name.
		if (! ::GetLocaleInfo (MAKELCID (ulLangId, SORT_DEFAULT), LOCALE_SLANGUAGE, strLangName, sizeof (strLangName)))
			::sprintf (strLangName, "%04x", fd.cFileName);

		g_vecLanguages.push_back (CLangData ());
		CLangData & ld = g_vecLanguages.back ();
		ld.liLangId = ulLangId;
		ld.strRLL.swap (strFilter);
		ld.strName = strLangName;

		if (ulLangId == GetSetting ("Language", (DWORD) 0x409))
			g_cCurrentLanguage = g_vecLanguages.size () - 1;
	} while (::FindNextFile (hFind, & fd));

	::FindClose (hFind);

	// Activate the language.
	ActivateLanguage (g_cCurrentLanguage);
}

size_t GetLanguagesNum () {
	return g_vecLanguages.size ();
}

size_t GetCurrentLanguage () {
	return g_cCurrentLanguage;
}

const string_t & GetLanguageName (size_t _cIdx) {
	assert (_cIdx < g_vecLanguages.size ());
	return g_vecLanguages [_cIdx].strName;
}

void ActivateLanguage (size_t _cIdx) {
	assert (_cIdx < g_vecLanguages.size ());

	if (_cIdx == g_cCurrentLanguage)
		return;

	g_cCurrentLanguage = _cIdx;
	SaveSetting ("Language", (DWORD) g_vecLanguages [_cIdx].liLangId);

	// Free previous RLL, if any.
	if (g_hResInst != g_hInst && g_hResInst)
		::FreeLibrary (g_hResInst);

	// Load new RLL.
	if (g_vecLanguages [_cIdx].liLangId == c_liEnglishUS)
		g_hResInst = g_hInst;
	else
		g_hResInst = ::LoadLibrary (g_vecLanguages [_cIdx].strRLL.c_str ());//, NULL, LOAD_LIBRARY_AS_DATAFILE);

	// Refresh menu.
	if (g_hWnd) {
		const HMENU hOldMenu = ::GetMenu (g_hWnd);
		const HMENU hMenu = LoadMenu (IDM_MAIN);
		if (hMenu && hMenu != hOldMenu) {
			::SetMenu (g_hWnd, hMenu);
			::DestroyMenu (hOldMenu);

			InitMenu ();
		}
	}

	// TODO: Refresh status, title etc ??
}

/////////////////////////////////

typedef std::map<size_t, const char *> mapStrings_t;
static mapStrings_t g_mapStrings;

const char * GetStr (size_t _cId) {
	mapStrings_t::iterator i = g_mapStrings.find (_cId);
	if (i != g_mapStrings.end ())
		return i->second;

	TCHAR strBuf [256];
	const size_t cLen = ::LoadString (g_hResInst, _cId, strBuf, sizeof (strBuf)/sizeof (TCHAR));
	if (cLen == 0) {
		const size_t cLenEn = ::LoadString (g_hInst, _cId, strBuf, sizeof (strBuf)/sizeof (TCHAR));
		if (cLenEn == 0) {
			assert (false);
			return "";
		}
	}

	char * const str = new char [cLen + 1];
	::strncpy (str, strBuf, cLen);
	str [cLen] = '\0';

	g_mapStrings.insert (mapStrings_t::value_type (_cId, str));
	return str;
}

void LoadString (UINT _uiString, char * _strBuf, size_t _cBufSize) {
	const char * const str = GetStr (_uiString);
	::strncpy (_strBuf, str, _cBufSize);
}

HMENU LoadMenu (WORD _wID) {
	// TODO: check resource availability!
	return ::LoadMenu (g_hResInst, MAKEINTRESOURCE (_wID));
}

HIMAGELIST LoadImageList (WORD _wID, int _nSize, COLORREF _colMask) {
	return ::ImageList_LoadImage (g_hResInst, MAKEINTRESOURCE (_wID), _nSize, 4, _colMask, IMAGE_BITMAP, LR_CREATEDIBSECTION);
}


INT_PTR DlgBox (WORD _wID, HWND _hWndParent, DLGPROC _pDlgProc, LPARAM _dwInitParam) {
	// TODO: check resource availability!
	return ::DialogBoxParam (g_hResInst, MAKEINTRESOURCE (_wID), _hWndParent, _pDlgProc, _dwInitParam);
}

INT_PTR DlgBox (WORD _wID, HWND _hWndParent, DLGPROC _pDlgProc) {
	// TODO: check resource availability!
	return ::DialogBox (g_hResInst, MAKEINTRESOURCE (_wID), _hWndParent, _pDlgProc);
}

HWND CreateDlg (WORD _wID, HWND _hWndParent, DLGPROC _pDlgProc, LPARAM _dwInitParam) {
	// TODO: check resource availability!
	return ::CreateDialogParam (g_hResInst, MAKEINTRESOURCE (_wID), _hWndParent, _pDlgProc, _dwInitParam);
}

HWND CreateDlg (WORD _wID, HWND _hWndParent, DLGPROC _pDlgProc) {
	// TODO: check resource availability!
	return ::CreateDialog (g_hResInst, MAKEINTRESOURCE (_wID), _hWndParent, _pDlgProc);
}